import { FormulaError } from './formula-error';
import { OperateSymbol, TAllTypes, IValue, IValueNumber } from './types';
import { typeofValue } from './utils';
import Decimal from 'decimal.js';
type NumVal = string | number;
/**
 * @description 加
 */
export const addDec = (a: NumVal = 0, b: NumVal = 0): number => {
  return Number(new Decimal(a).add(new Decimal(b)));
};
/**
 * @description 减
 */
export const subDec = (a: NumVal = 0, b: NumVal = 0): number => {
  return Number(new Decimal(a).sub(new Decimal(b)));
};
/**
 * @description 乘
 */
export const mulDec = (a: NumVal = 0, b: NumVal = 0): number => {
  return Number(new Decimal(a).mul(new Decimal(b)));
};
/**
 * @description 除
 */
export const divDec = (a: NumVal = 0, b: NumVal = 0): number => {
  return Number(new Decimal(a).div(new Decimal(b)));
};
export function calculate(operate: OperateSymbol, vals: TAllTypes[]): TAllTypes {
  if (vals.length !== 2 || vals[0].type !== 'value' || vals[1].type !== 'value') {
    throw new FormulaError('#VALUE!');
  }
  if (operate === '!=') {
    return { type: 'value', dataType: 'boolean', value: String((vals[0] as IValue).value) != String((vals[1] as IValue).value) }
  }
  if (operate === '==') {
    return { type: 'value', dataType: 'boolean', value: String((vals[0] as IValue).value) == String((vals[1] as IValue).value) }
  }
  if (typeofValue(vals[0]) !== 'number' || typeofValue(vals[1]) !== 'number') {
    throw new FormulaError('#VALUE!', { msg: 'params is wrong!', vals: vals });
  }
  let val1 = (vals as IValueNumber[])[0].value;
  let val2 = (vals as IValueNumber[])[1].value;
  if (operate === '+') {
    return { type: 'value', value: addDec(val1, val2), dataType: 'number' };
  }
  if (operate === '-') {
    return { type: 'value', dataType: 'number', value: subDec(val1, val2) };
  }
  if (operate === '*') {
    return { type: 'value', dataType: 'number', value: mulDec(val1, val2) };
  }
  if (operate === '/') {
    if (val2 === 0) {
      throw new FormulaError('#DIV/0!', { vals: vals });
    }
    return { type: 'value', dataType: 'number', value: divDec(val1, val2) };
  }
  if (operate === '**') {
    return { type: 'value', dataType: 'number', value: Decimal.pow(val1, val2).toNumber() };
  }
  if (operate === '%') {
    return { type: 'value', dataType: 'number', value: new Decimal(val1 % val2).toNumber() };
  }
  if (operate === '>') {
    return { type: 'value', dataType: 'boolean', value: vals[0] > vals[1] }
  }
  if (operate === '>=') {
    if (vals[0] === undefined || vals[1] === undefined) {
      throw new FormulaError('#N/A', { operate: '!=', info: vals })
    }
    return { type: 'value', dataType: 'boolean', value: vals[0] >= vals[1] }
  }
  if (operate === '<') {
    if (vals[0] === undefined || vals[1] === undefined) {
      throw new FormulaError('#N/A', { operate: '!=', info: vals })
    }
    return { type: 'value', dataType: 'boolean', value: vals[0] < vals[1] }
  }
  if (operate === '<=') {
    if (vals[0] === undefined || vals[1] === undefined) {
      throw new FormulaError('#N/A', { operate: '!=', info: vals })
    }
    return { type: 'value', dataType: 'boolean', value: vals[0] <= vals[1] }
  }
  throw new FormulaError('#UNKOWN!', { msg: 'unkown operate', operate: operate, vals: vals });
}